package org.sdnstproject.interlayer.interlayerProxy;

import java.io.IOException;
import java.net.*;

import org.sdnstproject.interlayer.OF13Protocal.FuFeaturesReply;
import org.sdnstproject.interlayer.openflowfuzzing.Strategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

public class InterlayerProxy implements Runnable {
	private static final Logger log = LoggerFactory.getLogger(InterlayerProxy.class);
    private ServerSocket socket;
    private int interlayerPort;
    public volatile boolean running = true;
    public volatile boolean stop = false;
    public String controllerIP;
    public int controllerPort;
    public MsgHander msgHander = null;
    public ThreadPoolExecutor pool;
    public Strategy strategy;
    public ArrayList<SingleConnection> theads;

    public InterlayerProxy(String ip, int interlayerPort, int controllerPort,ThreadPoolExecutor pool, Strategy strategy) {
        this.interlayerPort = interlayerPort;
        this.controllerIP = ip;
        this.controllerPort = controllerPort;
        this.pool = pool;
        this.strategy = strategy;
        this.theads = new ArrayList<SingleConnection>();
    }

    public void Stop() {
    	stop = true;
    	for(SingleConnection thread:theads) {
    		thread.running = false;
    	}
    	running = false;
    }
    
    public void run() {
    	
    	log.info("[SwitchToInterlayer] Listening switches on " + this.interlayerPort);
        try{
            this.socket = new ServerSocket(interlayerPort);
            socket.setReuseAddress(true);
        } catch (IOException e){
            e.printStackTrace();
            log.info("[SocketProxy] create ServerSocket failed");
        }
        if (this.socket == null) {
            log.info("[SocketProxy] start serverSocket failed");
        } else {
            log.info("[SocketProxy] start serverSocket success");
        }

        while(running && !Thread.currentThread().isInterrupted()) {
            try {
            	Socket switchConnect =  socket.accept();
            	if(stop) continue;
                log.info("[SwitchToInterlayer] Switch connected from  " + switchConnect.toString());
                SingleConnection switchToInterlayer = new SingleConnection(switchConnect, strategy);
                SingleConnection interToController = new SingleConnection(controllerIP, controllerPort, strategy);
                interToController.isTocontroller = true;
                switchToInterlayer.other = interToController;
                interToController.other = switchToInterlayer;
                pool.execute(switchToInterlayer);
                pool.execute(interToController);
                theads.add(switchToInterlayer);
                theads.add(interToController);
            } catch (IOException e) {
            	e.printStackTrace();
                log.info("[SocketProxy] accept socket error");
                break;
            }
        }
    }
}

